/*
 * Copyright (C) 2020 The LINN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.juqimiao.linn.extension;

import com.juqimiao.linn.context.ApplicationContextWrapperI;
import com.juqimiao.linn.context.BusinessPoint;
import com.juqimiao.linn.exception.FrameworkException;
import com.juqimiao.linn.logging.Logger;
import com.juqimiao.linn.registry.RegistryI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Map;

/**
 * 用于注册Extension的类。
 *
 * @author  Collin Cai
 */
@Component("extension")
@Order
public class ExtensionRegistry implements RegistryI {

    private static final String TYPE_CHECK_ERROR =
            "%s didn't implement from the interface which named %s was setup in $s Annotation";
    private ApplicationContextWrapperI applicationContextWrapper;

    private ExtensionKeeper extensionKeeper;

    private Logger logger = Logger.getLogger(ExtensionRegistry.class);
    @Autowired
    public ExtensionRegistry(ApplicationContextWrapperI applicationContextWrapper, ExtensionKeeper extensionKeeper) {
        this.applicationContextWrapper = applicationContextWrapper;
        this.extensionKeeper = extensionKeeper;
    }

    @Override
    public void register() {
        if (applicationContextWrapper == null) {
            // Todo: Put log here.
            return;
        }

        Map<String, ExtensionPointI> extensions = applicationContextWrapper.getBeansOfType(ExtensionPointI.class);
        if (extensions != null && extensions.size() > 0) {
            extensions.forEach((key, extension) -> {
                logger.info(String.format("Begin register Extension: %s", extension));
                Class<?> extensionClz = extension.getClass();
                Extension extensionAnn = extensionClz.getDeclaredAnnotation(Extension.class);
                BusinessPoint businessPoint = BusinessPoint.valueOf(extensionAnn.BusinessId(),
                        extensionAnn.useCase(),
                        extensionAnn.scenario());
                /* 需要通过它指明扩展点接口。 */
                String pointInterfaceName = extensionAnn.Interface().getName();
                checkPointInterface(extensionClz, pointInterfaceName);
                ExtensionCoordinator coordinate = new ExtensionCoordinator(pointInterfaceName, businessPoint.getUniqueId());
                extensionKeeper.getExtensions().put(coordinate, extension);
                logger.info(String.format("End register Extension: %s", extension));
            });
        }
    }

    private void checkPointInterface(Class<?> extensionClz, String pointInterfaceName) {
        Class<?>[] interfaceClzes = extensionClz.getInterfaces();
        if (interfaceClzes != null || interfaceClzes.length > 0) {
            Arrays.stream(interfaceClzes).forEach(ac -> {
                String targetName = ac.getName();
                String extensionName = Extension.class.getName();
                if (!targetName.equals(pointInterfaceName)) {
                    throw new FrameworkException(String.format(TYPE_CHECK_ERROR,
                            targetName,
                            pointInterfaceName,
                            extensionName));
                }
            });
        }
    }
}

